let a1: number = 123
a1 = 11

type xdfre = { x: number, y: number }
interface xdf { x: number, y: number } // 类型别名的写法 type和interface 相当于let,推荐使用interface
// 对于 type来说，更多的是对类型的一种复用，比如在项目中需要用到一些比较复杂的或者书写起来很长的类型，我们可以使用 type来直接引用该类型
// 而对于 interface来说，它是正儿八经的用来定义接口类型（约束数类型和属性）的，且接口类型是支持继承和声明合并的。

const dfgr = (data: xdf) => {
  console.log("loh")
  return Math.sqrt(data.x ** 2 + data.y ** 2) // Math.sqrt() 函数返回一个数的平方根， **：乘方 *：乘法
}
dfgr({ x: 1, y: 2 })

// vsCode中 打开设置-搜索quote 找到typescript设置single单引号,安装prettier-Code formatter
// 全局安装 npm install typescript -g  npm install ts-node -g  
// 运行ts文件：ts-node xx.ts

let count: number = 98
count.toString()
console.log(count)

interface point {
  x: number,
  y: number
}

let counts: point = {
  x: 1, y: 1
}
counts.x

// 基础类型：number string null undefined symbol boolean void(是空的意思) never（这个函数永远不能执行到最后）
// 对象类型：{} class function []
const data: {
  x: number,
  y: string
} = {
  x: 123,
  y: 'uik'
}
const nums: number[] = [1, 2, 3]
const nums1: string[] = ['1', '2', '3']
class Person { }
const datas: Person = new Person()
const spijk: () => number = () => {
  return 123
}


// type annotation 类型注解，我们来告诉TS变量是什么类型
// type inference 类型推断，TS会自动的去尝试分析变量的类型
// 如果TS能够自动分析变量的类型，我们就什么也不用做了
// 如果TS无法分析变量的类型的话，我们就需要使用类型注解

function getTotal(num1: number, num2: number) {
  return num1 + num2
}
const total = getTotal(1, 2)

// typescript三种函数定义方式
function hello() { }
const hello1 = function () { }
const hello2 = () => { }

const add = (first: number, second: number): number => {
  return first + second
}
const tool = add(1, 1)

// never 函数不会执行到最后
const errorEmitter = (): never => {
  while (true) { } // never可以配合while(循环)使用
  throw new Error() // 抛出异常
  console.log('你好')
}
// 结构函数的写法
const adf = ({ first, second }: { first: number, second: number }): number => {
  return first + second
}
const total1 = adf({ first: 1, second: 2 })

function getNumber({ first }: { first: number }): number {
  return first
}
const counti = getNumber({ first: 1 })

// 函数赋值的俩种写法，效果一样的。
const func = (str: string): number => {
  return parseInt(str)
}
const func1: (str: string) => number = (str) => {
  return parseInt(str)
}

let h1: number | string = 123 // h1可能是数字类型也可能是字符换类型
h1 = '234'
const arr: (number | string)[] = [1, '2', 3] // 数组里既可以有数字类型也可以有字符串类型

type Info = {
  name: string;
  age: number
}
const objectArr: Info[] = [{
  name: 'dfer',
  age: 19
}]

class Teacher {
  name: string;
  age: number
}
const objectArr1: Teacher[] = [
  new Teacher(),
  {
    name: 'hgjf',
    age: 9
  }
]

// 元组 typle
const teacherInfo: [number, number, string] = [12, 13, 'bjd']
// csv
const teacherInfoList: ([string, number, number])[] = [
  ['wangkun', 18, 23],
  ['wangdf', 8, 13],
  ['liuhua', 28, 14],
]
// interface和type相类似，但并不完全一致
interface Person {
  name: string;
  age?: number; // ?代表这条属性可有可无
  readonly high: number; // readonly 代表只读属性，不能用于赋值
  [propName: string]: any; // 一个字符串的属性名，的任何数据类型
  say(): string
}
// teacher继承Person
interface teacher extends Person {
  teach(): string
}
// interface定义方法
interface sayHi {
  (word: string): string
}
// 一个类应用一个接口interface
class User implements Person {
  name: string;
  high: 99;
  say() {
    return 'dvfv'
  }
}
const personList: Person = {
  name: 'dddv',
  age: 11,
  high: 12,
  mex: 'xxx',
  say() {
    return 'xccc'
  },
  teach() {
    return 'dvfd'
  }
}

const df: sayHi = (word: string) => {
  return word
}
// 定义类----父类
class Person1 {
  name: 'angkun';
  getName() {
    return this.name
  }
}
// 继承类--子类
class Person2 extends Person1 {
  getTeacherName() {
    return 'ddsvdv'
  }
  getName1() {
    return super.getName() + 'lee' // super代表父类，重写父类的方法
  }
}

const teacher = new Person1()
console.log(teacher.getName())

// publice 允许在类的内外被调用
// private 只允许在类内被调用
// protected 只允许在类内及继承的子类中使用
// constructor: new 实例后马上执行

class Person3 {
  public name: string;
  // 传统写法
  // public age: number;
  // constructor(age: number) { 
  //   this.age = age
  // }
  // 简化写法
  constructor(public age: number) { }
  private sayHi() {
    this.name;
    console.log('hi')
  }
  protected sayHi1() {
    this.name;
    console.log('hi')
  }
}
class Person4 extends Person3 {
  constructor(public name: string) {
    super(11) // 子类如果也想用构造器，必须super()引入，并传入父类的要求的数值
  }
  public sayBye() {
    this.sayHi1()
  }
}
const person = new Person3(13)
person.name = 'dds'

// get set 可以把私有变成共有，并进行改造
class Person5 {
  constructor(private _name: string) { }
  get name1() {
    return this._name + 'dd'
  }
  set name2(name: string) {
    const realName = name.split('')[0]
    this._name = realName
  }
}
const persons = new Person5('wangkun')
persons.name1
persons.name2 = 'wagkunkun'
//抽象类  abstract，只能被继承
abstract class Geom {
  width: number;
  getType() {
    return 'dds'
  }
  abstract getAre(): number
}

class Circli extends Geom {
  getAre(): number {
    return 123
  }
}
class Square extends Geom {
  getAre(): number {
    return 456
  }
}

// import引入js编写的组件后，在TS中可以安装npm install @types/xx -D（翻译文件：ts），在引入就不会报错了

// 这种数据格式取值
const datay = {
  de: {
    sd: '11',
    dc: 2121
  }
}
console.log(datay.de?.sd)

// TS类型断言
// TypeScript中的类型断言是一种将变量或表达式的类型强制转换为开发者指定的类型的方式。可以使用尖括号（<>）语法或者as语法进行类型断言。

// 使用尖括号语法的类型断言：
let str1: any = "hello";
let len1: number = (<string>str1).length;
// 使用as语法的类型断言：
let str2: any = "hello";
let len2: number = (str2 as string).length;

// ?相关代码
// 当使用A对象属性A.B时，如果无法确定A是否为空，则需要用A?.B，表示当A有值的时候才去访问B属性，没有值的时候就不去访问，如果不使用?则会报错

const user = {
  account: '111'
};
const user1 = null
console.log(user1.account)   // 报错
console.log(user?.account)  // 可以用作判断，当user对象不为空的时候就会取值user.account

// ?:是指可选参数，可以理解为参数自动加上undefined 
export interface RequestForm {
  pageSize: number
  pageNumber: number
  name?: string // 可选属性
  sex?: string // 可选属性
}

// ?? 和 || 的意思有点相似，但是又有点区别，?? 相较 || 比较严谨，当值等于0的时候 || 就把他给排除了，但是 ?? 不会.

console.log(null || 1) // 1
console.log(null ?? 1) // 1

console.log(undefined || 1) //1
console.log(undefined ?? 1) //1

console.log(0 || 1) // 1
console.log(0 ?? 1) // 0 

const foo = null ?? 'default string';
console.log(foo); // 输出: "default string"

const baz = 0 ?? 42;
console.log(baz); // 输出: 0
// 比如要赋值判断一个对象是否存在可以写成
let is_valid = (test) ? true : false;
//但是还有个更加简单的写法
// let is_valid = !!test;

console.log(!!(0 + 0)) // 输出: false
console.log(!!(3 * 3)) // 输出: true

// ! 运算符:
//含义: 逻辑非运算符，用于取反一个布尔值或将一个值转换为布尔类型并取反。用法示例:
const isTrue = true;
const isFalse = false;
console.log(!isTrue); // 输出: false 
console.log(!isFalse); // 输出: true
// !! 运算符:含义: 用于将一个值转换为对应的布尔值（强制类型转换）。用法示例:
const value = "Hello";
console.log(!!value); // 输出: true，任何非空字符串在布尔上下文中都是真值

// !.非空类型断言: 含义：!.非空类型断言，表示确定某个标识符是有值的:用法示例：

function aa(value?: string) {
  console.log(value!.length);
  // console.log(value.length); //错误提醒:value is possibly 'undefined'.
}
aa('ppp')；
// 注意： !.不传值, 编译JS后会报错, 建议使用?. 替代 !